<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <svg id="svg"></svg>
</body>

</html>
<script src="http://d3js.org/d3.v6.min.js"></script>
<script>
  let width = 600,
    height = 600;
  let svg = d3.select('#svg').attr('width', width).attr('height', height);
  let g = svg.append('g');
  let colorAry = d3.schemeCategory10;
  // nodes 是控制节点的数据
  // edges 是控制边的数据
  let nodes = [{
      name: "湖南邵阳"
    },
    {
      name: "山东莱州"
    },
    {
      name: "广东阳江"
    },
    {
      name: "山东枣庄"
    },
    {
      name: "泽"
    },
    {
      name: "恒"
    },
    {
      name: "鑫"
    },
    {
      name: "明山"
    },
    {
      name: "班长"
    }
  ]
  let edges = [{
      source: 0,
      target: 4,
      relation: "籍贯",
      value: 1.3
    },
    {
      source: 4,
      target: 5,
      relation: "舍友",
      value: 1
    },
    {
      source: 4,
      target: 6,
      relation: "舍友",
      value: 1
    },
    {
      source: 4,
      target: 7,
      relation: "舍友",
      value: 1
    },
    {
      source: 1,
      target: 6,
      relation: "籍贯",
      value: 2
    },
    {
      source: 2,
      target: 5,
      relation: "籍贯",
      value: 0.9
    },
    {
      source: 3,
      target: 7,
      relation: "籍贯",
      value: 1
    },
    {
      source: 5,
      target: 6,
      relation: "同学",
      value: 1.6
    },
    {
      source: 6,
      target: 7,
      relation: "朋友",
      value: 0.7
    },
    {
      source: 6,
      target: 8,
      relation: "职责",
      value: 2
    }
  ]

  let mySimulation = d3.forceSimulation()
    .force('link', d3.forceLink()) // 给连线假弹力模型
    .force('charge', d3.forceManyBody()) // 给节点添加电荷力模型
    .force("center", d3.forceCenter()); // 添加向心力模型

  //mySimulation 是来创造力向导图的一个函数 
  let nodeObj = mySimulation.nodes(nodes);
  console.log(nodes, nodeObj)
  // nodeObj.on('tick',function(){
  //   console.log(555)
  // })
  mySimulation.force('link').links(edges).distance(function (d) {
    return d.value * 100
  })
  mySimulation.force('center').x(width / 2).y(height / 2)

  let lines = g.append('g').selectAll('line')
    .data(edges)
    .enter()
    .append('line')
    .attr('stroke', function (d, i) {
      return colorAry[i]
    })

  let texts = g.append('g').selectAll('text')
    .data(edges)
    .enter()
    .append('text')
    .attr('text-anchor', 'middle')
    .text(function (d) {
      return d.relation
    })
  // .attr('stroke',function(d,i){
  //   return colorAry[i]
  // })

  let gs = g.selectAll('.gs').data(nodes).enter().append('g').classed('gs', true);
  gs.append('circle').attr('r', 10).attr('fill', function (d, i) {
    return colorAry[i]
  })
  gs.append('text').text(function (d) {
    return d.name
  })

  nodeObj.on('tick', function () {
    lines.attr('x1', function (d, i) {
        // console.log(d)
        return d.source.x
      })
      .attr('y1', function (d, i) {
        return d.source.y
      })
      .attr('x2', function (d, i) {
        return d.target.x
      })
      .attr('y2', function (d, i) {
        return d.target.y
      })

    texts.attr('x', function (d, i) {
        return (d.source.x + d.target.x) / 2
      })
      .attr('y', function (d, i) {
        return (d.source.y + d.target.y) / 2
      })
    gs.attr('transform', function (d, i) {
      // console.log(d)
      return `translate(${d.x},${d.y})`
    })
  })

  gs.call(d3.drag().on('start', function (e, d) {
    mySimulation.alphaTarget(0.8).restart() // 重起仿真器
    console.log(e, d)
    // 若想要节点固定到到某个位置 只需要设置 d.fx 和 d.fy即可
    d.fx = d.x; // 
    d.fy = d.y;
  })
  .on('drag',function(e,d){
    d.fx = e.sourceEvent.x; // 
    d.fy = e.sourceEvent.y;
  })
  .on('end',function(e,d){
    mySimulation.alphaTarget(0)
    d.fx = null; // 松开后 解除固定
    d.fy = null;
  })
  )
</script>